package repos

import javax.inject.Inject

import exceptions.{BusinessDataEmptyError, BusinessException}
import models.{Dict, DictItem, DictWithDictItem}
import org.joda.time.DateTime
import org.sedis.Pool
import play.api.db.slick.DatabaseConfigProvider
import repos.Tables.{DictItemTable, DictTable}
import slick.backend.DatabaseConfig
import slick.driver.JdbcProfile

import scala.concurrent.ExecutionContext
import scala.reflect.ClassTag

class DictRepository @Inject()(databaseConfigProvider: DatabaseConfigProvider,
                               dictItemRepository: DictItemRepository,
                               cache: Pool)
  extends BaseRepository[Dict,DictTable](Tables.dicts, cache) {
  override val dbConfig: DatabaseConfig[JdbcProfile] = databaseConfigProvider.get[JdbcProfile]

  import driver.api._

  def save(t: DictWithDictItem)(implicit ec: ExecutionContext) = {
    if (t.dictCode.size == 0)
      throw new BusinessException(-10, "字典代码不能为空")
    if (t.dictName.size == 0)
      throw new BusinessException(-10, "字典名称不能为空")
    val dict = Dict(dictCode = t.dictCode, dictName = t.dictName, dictType = t.dictType,
      isDeleted = t.isDeleted, joinTime = Some(DateTime.now()), dictDescription = t.dictDescription)
    val run2 = (
      for {
        d <- (q.returning(q.map(_.id)).into((qx, id) => qx.copy(id = Some(id)))) += dict
        ddid <- t.addDictItems.map { dis =>
          val ndis = dis.map(di => di.copy(dictId = d.id.get, joinTime = d.joinTime))
          (dictItemRepository.q.returning(dictItemRepository.q.map(_.id)).into((qx, id) => qx.copy(id = Some(id)))) ++= ndis
        }.getOrElse(DBIO.seq())
      } yield (d, ddid)
      ).transactionally
    val rst = db.run(run2).map { case (d: Dict, dis: Seq[DictItem]) =>
      DictWithDictItem(d.dictCode, d.dictName, d.dictType, d.joinTime, d.isDeleted, d.dictDescription, d.id, d.updateTime,
        Option(dis))
    }
    rst
  }

  override def realRemove(id: Int)(implicit abc: ClassTag[Dict], executionContext: ExecutionContext) = {
    val run = {
      for {
        removeDiNum <- dictItemRepository.qq.filter(di => di.dictId === id).delete
        removeNum <- this.realRemoveByIdQ(id)
      } yield removeNum + removeDiNum
    }.transactionally

    db.run(run)
  }

  def update(t: DictWithDictItem)(implicit executionContext: ExecutionContext) = {
    if (t.dictCode.size == 0)
      throw new BusinessDataEmptyError("字典代码不能为空")
    if (t.dictName.size == 0)
      throw new BusinessDataEmptyError("字典名称不能为空")

    val dict = Dict(t.dictCode, t.dictName, t.dictType, t.joinTime, t.isDeleted, t.dictDescription, t.id, t.updateTime)
    val now = DateTime.now()

    val run = (for {
      dictCodeExistCount <- this.qq.filter(d=> d.dictCode === t.dictCode && d.id =!= dict.id.get).size.result
      updateNum <- if (dictCodeExistCount > 0) throw new BusinessException(-11, "字典代码已存在") else {
        this.updateQ(dict)
      }
      _ <-
      DBIO.seq(t.addDictItems.map { dis =>
        val ndis = dis.map { di =>
          di.copy(dictId = dict.id.get, joinTime = Some(now))
        }
        dictItemRepository.q ++= ndis
      }.getOrElse(DBIO.seq()),
        t.updateDictItems.map { dis =>
          val ndis = dis.map { di =>
            di.copy(updateTime = Some(now))
          }
          dictItemRepository.q ++= ndis
        }.getOrElse(DBIO.seq()),
        t.removeDictItems.map { dis =>
          val ndid = dis.map { di =>
            di.id.get
          }
          dictItemRepository.q.filter(d => d.id.inSet(ndid)).delete
        }.getOrElse(DBIO.seq())
      )
    } yield updateNum.asInstanceOf[TotalCount]).transactionally
    db.run(run)
  }
}

class DictItemRepository @Inject()(databaseConfigProvider: DatabaseConfigProvider,
                                   cache: Pool)
  extends BaseRepository[DictItem,DictItemTable](Tables.dictItems, cache) {
  override val dbConfig: DatabaseConfig[JdbcProfile] = databaseConfigProvider.get[JdbcProfile]

}

